home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus Special 26 / AMIGAplus Sonderheft 26 (2000)(Falke)(DE)(Track 1 of 2)[!].iso / Tools / SFX-Player / Mpeg / mpegaudio_datatype / dispatch.c < prev    next >
C/C++ Source or Header  |  1999-03-29  |  19KB  |  609 lines

  1.  
  2. /*
  3. **
  4. **  $VER: dispatch.c 1.1 (9.11.97)
  5. **  mpegaudio.datatype 1.1
  6. **
  7. **  Dispatch routine for a DataTypes class
  8. **
  9. **  Written 1996/97 by Roland 'Gizzy' Mainz
  10. **  Original example source from David N. Junod
  11. **
  12. */
  13.  
  14. /* main includes */
  15. #include "classbase.h"
  16. #include "classdata.h"
  17.  
  18. /*****************************************************************************/
  19.  
  20. /* This switch would modify the datatype to use "mpega" */
  21. #if 0
  22. #define USE_MPEGA 1
  23. #endif
  24.  
  25. /*****************************************************************************/
  26.  
  27. /* local prototypes */
  28. static                 LONG              LoadSample( struct ClassBase *, Object * );
  29. static                 void              mysprintf( struct ClassBase *, STRPTR, STRPTR, ... );
  30.  
  31. #ifndef NO_ENCODER
  32. static                 ULONG             SaveMPEGAudio( struct ClassBase *, Object *, struct dtWrite * );
  33. #endif /* NO_ENCODER */
  34.  
  35. /*****************************************************************************/
  36.  
  37. /* Create "mpegaudio.datatype" BOOPSI class */
  38. struct IClass *initClass( struct ClassBase *cb )
  39. {
  40.     struct IClass *cl;
  41.  
  42.     /* Create our class... */
  43.     if( cl = MakeClass( MPEGAUDIODTCLASS, SOUNDDTCLASS, NULL, (ULONG)sizeof( struct MPEGAudioInstData ), 0UL ) )
  44.     {
  45. #define DTSTACKSIZE (16384UL)
  46.       cl -> cl_Dispatcher . h_Entry    = (HOOKFUNC)StackSwapDispatch; /* see stackswap.c */
  47.       cl -> cl_Dispatcher . h_SubEntry = (HOOKFUNC)Dispatch;          /* see stackswap.c */
  48.       cl -> cl_Dispatcher . h_Data     = (APTR)DTSTACKSIZE;           /* see stackswap.c */
  49.       cl -> cl_UserData                = (ULONG)cb;                   /* class library base as expected by datatypes.library */
  50.  
  51.       AddClass( cl );
  52.     }
  53.  
  54.     return( cl );
  55. }
  56.  
  57. /*****************************************************************************/
  58.  
  59. /* class dispatcher */
  60. DISPATCHERFLAGS
  61. ULONG Dispatch( REGA0 struct IClass *cl, REGA2 Object *o, REGA1 Msg msg )
  62. {
  63.     struct ClassBase     *cb = (struct ClassBase *)(cl -> cl_UserData);
  64.     ULONG                 retval = 0UL;
  65.  
  66.     switch( msg -> MethodID )
  67.     {
  68. /****** mpegaudio.datatype/OM_NEW ********************************************
  69. *
  70. *    NAME
  71. *        OM_NEW -- Create a mpegaudio.datatype object.
  72. *
  73. *    FUNCTION
  74. *        The OM_NEW method is used to create an instance of the
  75. *        mpegaudio.datatype class. This method is passed to the superclass
  76. *        first. After this, mpegaudio.datatype loads the sample using
  77. *        "mpega" and the 8svx.datatype.
  78. *
  79. *    ATTRIBUTES
  80. *        The following attributes can be specified at creation time.
  81. *
  82. *        DTA_SourceType (ULONG) -- Determinates the type of DTA_Handle
  83. *            attribute. Only DTST_FILE is supported.
  84. *            If any other type was set in a given DTA_SourceType,
  85. *            OM_NEW will be rejected.
  86. *            Defaults to DTST_FILE.
  87. *
  88. *        DTA_Handle -- For DTST_FILE, a BPTR to a lock is expected by
  89. *            datatypesclass, which will convert this into a filehandle.
  90. *            A DTST_RAM (create empty object) source type requires a NULL
  91. *            handle.
  92. *
  93. *    NOTE
  94. *        If the datatype was compiled with the NO_ENCODER flag set,
  95. *        DTA_SourceType == DTST_RAM causes OM_NEW to reject the method.
  96. *
  97. *    RESULT
  98. *        If the object was created a pointer to the object is returned,
  99. *        otherwise NULL is returned.
  100. *
  101. ******************************************************************************
  102. *
  103. */
  104.       case OM_NEW:
  105.       {
  106.           struct TagItem *ti;
  107.  
  108.           /* We only support DTST_FILE or DTST_RAM as source type */
  109.           if( ti = FindTagItem( DTA_SourceType, (((struct opSet *)msg) -> ops_AttrList) ) )
  110.           {
  111.             if( ((ti -> ti_Data) != DTST_FILE)
  112. #ifndef NO_ENCODER
  113. && ((ti -> ti_Data) != DTST_RAM)
  114. #endif /* !NO_ENCODER */
  115.  
  116. )
  117.             {
  118.               SetIoErr( ERROR_OBJECT_WRONG_TYPE );
  119.  
  120.               break;
  121.             }
  122.           }
  123.  
  124.           /* This must not be a subclass of mpegaudio.datatype
  125.            * (not implemented yet)
  126.            */
  127.           if( o == (Object *)cl )
  128.           {
  129.             if( retval = DoSuperMethodA( cl, o, msg ) )
  130.             {
  131.               LONG error;
  132.  
  133.               /* Load sample... */
  134.               if( error = LoadSample( cb, (Object *)retval ) )
  135.               {
  136.                 /* Something went fatally wrong, dispose object */
  137.                 CoerceMethod( cl, (Object *)retval, OM_DISPOSE );
  138.                 retval = 0UL;
  139.               }
  140.  
  141.               SetIoErr( error );
  142.             }
  143.           }
  144.           else
  145.           {
  146.             /* Subclasses of mpegaudio.datatype are not implemented */
  147.             SetIoErr( ERROR_NOT_IMPLEMENTED );
  148.           }
  149.       }
  150.           break;
  151.  
  152. /****** mpegaudio.datatype/OM_DISPOSE ****************************************
  153. *
  154. *    NAME
  155. *        OM_DISPOSE -- Delete object
  156. *
  157. *    FUNCTION
  158. *        Frees the contents of the mpegvideo.datatype instance data
  159. *        and passes then the msg to the superclass.
  160. *
  161. *        This method deletes the embedded 8svx.datatype object and deletes
  162. *        the temporary 8SVX sample file created.
  163. *
  164. *    RESULT
  165. *        Returns 0 evertimes.
  166. *
  167. ******************************************************************************
  168. *
  169. */
  170.       case OM_DISPOSE:
  171.       {
  172.           struct MPEGAudioInstData *maid        = (struct MPEGAudioInstData *)INST_DATA( cl, o );
  173.           LONG                      saved_ioerr = IoErr(); /* save I/O error */
  174.  
  175.           /* Any embedded 8SVX/AIFF object ? */
  176. #ifdef USE_MPEGA
  177.           if( maid -> maid_AIFFObject )
  178.           {
  179.             /* Avoid that we free the sample data which belongs to the aiff.datatype object */
  180.             SetDTAttrs( o, NULL, NULL, SDTA_Sample, NULL, TAG_DONE );
  181.  
  182.             DisposeDTObject( (maid -> maid_AIFFObject) );
  183.           }
  184.  
  185.           /* Delete tmp AIFF file if we created one... */
  186.           if( strlen( (maid -> maid_AIFFName) ) )
  187.           {
  188.             DeleteFile( (maid -> maid_AIFFName) );
  189.           }
  190. #else
  191.           if( maid -> maid_8SVXObject )
  192.           {
  193.             /* Avoid that we free the sample data which belongs to the 8svx.datatype object */
  194.             SetDTAttrs( o, NULL, NULL, SDTA_Sample, NULL, TAG_DONE );
  195.  
  196.             DisposeDTObject( (maid -> maid_8SVXObject) );
  197.           }
  198.  
  199.           /* Delete tmp 8SVX file if we created one... */
  200.           if( strlen( (maid -> maid_8SVXName) ) )
  201.           {
  202.             DeleteFile( (maid -> maid_8SVXName) );
  203.           }
  204. #endif /* USE_MPEGA */
  205.  
  206.           /* Free outselves */
  207.           DoSuperMethodA( cl, o, msg );
  208.  
  209.           /* Restore I/O error */
  210.           SetIoErr( saved_ioerr );
  211.       }
  212.           break;
  213.  
  214.       case OM_UPDATE:
  215.       {
  216.           if( DoMethod( o, ICM_CHECKLOOP ) )
  217.           {
  218.             break;
  219.           }
  220.       }
  221.       case OM_SET:
  222.       {
  223.           /* Pass the attributes to the sound class and force a refresh if we need it */
  224.           if( retval = DoSuperMethodA( cl, o, msg ) )
  225.           {
  226. /* The following check statement isn't needed because OM_NEW does not allow subclasses of mpegaudio.datatype,
  227.  * therefore, we're always the top instance...
  228.  */
  229. #ifdef COMMENTED_OUT
  230.             /* Top instance ? */
  231.             if( OCLASS( o ) == cl )
  232. #endif /* COMMENTED_OUT */
  233.             {
  234.               struct RastPort *rp;
  235.  
  236.               /* Get a pointer to the rastport */
  237.               if( rp = ObtainGIRPort( (((struct opSet *)msg) -> ops_GInfo) ) )
  238.               {
  239.                 struct gpRender gpr;
  240.  
  241.                 /* Force a redraw */
  242.                 gpr . MethodID   = GM_RENDER;
  243.                 gpr . gpr_GInfo  = ((struct opSet *)msg) -> ops_GInfo;
  244.                 gpr . gpr_RPort  = rp;
  245.                 gpr . gpr_Redraw = GREDRAW_UPDATE;
  246.  
  247.                 DoMethodA( o, (Msg)(&gpr) );
  248.  
  249.                 /* Release the temporary rastport */
  250.                 ReleaseGIRPort( rp );
  251.  
  252.                 /* We did a refresh... */
  253.                 retval = 0UL;
  254.               }
  255.             }
  256.           }
  257.       }
  258.           break;
  259.  
  260. /****** mpegaudio.datatype/DTM_WRITE **********************************************
  261. *
  262. *    NAME
  263. *        DTM_WRITE -- Save data
  264. *
  265. *    FUNCTION
  266. *        This method saves the object's contents to disk.
  267. *
  268. *        If dtw_Mode is DTWM_IFF, the method is passed unchanged to the
  269. *        superclass, sound.datatype, which writes an IFF 8SVX sample.
  270. *
  271. *        If dtw_mode is DTWM_RAW, the object writes a MPEG audio stream to
  272. *        the filehandle given.
  273. *        (If the class library was compiled with the NO_ENCODER switch
  274. *        (not the default), result == 0 and resul2 == ERROR_NOT_IMPLEMENTED
  275. *        are returned).
  276. *
  277. *    TAGS
  278. *        None defined.
  279. *
  280. *    RESULT
  281. *        Returns 0 for failure (IoErr() returns result2), non-zero
  282. *        for success.
  283. *
  284. ******************************************************************************
  285. *
  286. */
  287.       case DTM_WRITE:
  288.       {
  289.           struct dtWrite *dtw;
  290.  
  291.           dtw = (struct dtWrite *)msg;
  292.  
  293.           /* Local data format requested ? */
  294.           if( (dtw -> dtw_Mode) == DTWM_RAW )
  295.           {
  296. /* Enable the followng code if you don't have an encoder implemented... */
  297. #ifdef NO_ENCODER
  298.             SetIoErr( ERROR_NOT_IMPLEMENTED );
  299.             retval = 0UL;
  300. #else
  301.             retval = SaveMPEGAudio( cb, o, dtw );
  302. #endif /* NO_ENCODER */
  303.           }
  304.           else
  305.           {
  306.             /* Pass msg to superclass (which writes an IFF 8SVX sample)... */
  307.             retval = DoSuperMethodA( cl, o, msg );
  308.           }
  309.       }
  310.           break;
  311.  
  312.       /* Let the superclass handle everything else */
  313.       default:
  314.       {
  315.           retval = DoSuperMethodA( cl, o, msg );
  316.       }
  317.           break;
  318.     }
  319.  
  320.     return( retval );
  321. }
  322.  
  323.  
  324. static
  325. LONG LoadSample( struct ClassBase *cb, Object *o )
  326. {
  327.     struct MPEGAudioInstData *maid  = (struct MPEGAudioInstData *)INST_DATA( (cb -> cb_Lib . cl_Class), o );
  328.     LONG                      error = 0L;
  329.     BPTR                      fh;               /* stream handle                                */
  330.     ULONG                     sourcetype;       /* type of stream (either DTST_FILE or DTST_RAM */
  331.     struct VoiceHeader       *vh;               /* obj's voice header                           */
  332.  
  333.     /* Get file handle, handle type and VoiceHeader */
  334.     if( GetDTAttrs( o, DTA_SourceType,    (&sourcetype),
  335.                        DTA_Handle,        (&fh),
  336.                        SDTA_VoiceHeader,  (&vh),
  337.                        TAG_DONE ) == 3UL )
  338.     {
  339.       switch( sourcetype )
  340.       {
  341.         case DTST_FILE:
  342.         {
  343.             /* We got all what we want (a filehandle) */
  344.         }
  345.             break;
  346.  
  347. #ifndef NO_ENCODER
  348.         case DTST_RAM:
  349.         {
  350.             /* Do nothing... */
  351.         }
  352.             break;
  353. #endif /* !NO_ENCODER */
  354.  
  355.         default:
  356.         {
  357.             /* unsupported source type */
  358.             error = ERROR_NOT_IMPLEMENTED;
  359.         }
  360.             break;
  361.       }
  362.  
  363.       /* Any error ? */
  364.       if( error == 0L )
  365.       {
  366. #ifdef USE_MPEGA
  367.         if( fh )
  368.         {
  369.           TEXT pipe_in[ 256 ],
  370.                cmd[ 256 ];
  371.           BPTR mpega_in;
  372.  
  373.           mysprintf( cb, pipe_in,                 "PIPE:MPEGAudio_in%lx",    o );
  374.           mysprintf( cb, (maid -> maid_AIFFName), "T:MPEGAudio_tmp%lx.aiff", o );
  375.           mysprintf( cb, cmd,                     "mpega:mpega -A -d4 -q0 -r -s -i -u -m -D -C %s %s", pipe_in, (maid -> maid_AIFFName) );
  376.  
  377.           if( mpega_in = Open( pipe_in, MODE_NEWFILE ) )
  378.           {
  379.             /* Start decoder "mpega" */
  380.             if( SystemTags( cmd, SYS_Input,  Open( "CON:////MPEG Audio DataType/auto/close/wait/inactive", MODE_NEWFILE ),
  381.                                  SYS_Output, NULL,
  382.                                  SYS_Asynch, TRUE,
  383.                                  TAG_DONE ) == 0L )
  384.             {
  385.               UBYTE buffer[ 4096 ];
  386.               LONG  numread;
  387.  
  388.               /* Feed "mpega" with data (througth the pipe) */
  389.               do
  390.               {
  391.                 if( (numread = Read( fh, buffer, sizeof( buffer ) )) != -1L )
  392.                 {
  393.                   (void)Write( mpega_in, buffer, numread );
  394.                 }
  395.               } while( numread == sizeof( buffer ) );
  396.             }
  397.             else
  398.             {
  399.               /* can't start "mpega" */
  400.               error = IoErr();
  401.             }
  402.  
  403.             Close( mpega_in );
  404.           }
  405.           else
  406.           {
  407.             /* can't open pipe */
  408.             error = IoErr();
  409.           }
  410.  
  411.           /* Success ? */
  412.           if( error == 0L )
  413.           {
  414. try:
  415.             maid -> maid_AIFFObject = NewDTObject( (maid -> maid_AIFFName), DTA_GroupID, GID_SOUND, TAG_DONE );
  416.  
  417.             /* This may happen if "mpega" has not been finished yet,,, */
  418.             if( ((maid -> maid_AIFFObject) == NULL) && (IoErr() == ERROR_OBJECT_IN_USE) )
  419.             {
  420.               /* Wait a 1/2 sec */
  421.               Delay( (TICKS_PER_SECOND / 2UL) );
  422.               goto try;
  423.             }
  424.  
  425.             if( maid -> maid_AIFFObject )
  426.             {
  427.               struct VoiceHeader *aiff_vh;
  428.               APTR                aiff_sample;
  429.               ULONG               aiff_samplelength;
  430.               ULONG               aiff_period;
  431.               ULONG               aiff_volume;
  432.  
  433.               if( GetDTAttrs( (maid -> maid_AIFFObject), SDTA_VoiceHeader,    (&aiff_vh),
  434.                                                          SDTA_Sample,         (&aiff_sample),
  435.                                                          SDTA_SampleLength,   (&aiff_samplelength),
  436.                                                          SDTA_Period,         (&aiff_period),
  437.                                                          SDTA_Volume,         (&aiff_volume),
  438.                                                          TAG_DONE ) == 5UL )
  439.               {
  440.                 /* Copy voiceheader. This point is very tricky because mpeg audio might not support all things... */
  441.                 *vh = *aiff_vh;
  442.  
  443.                 /* Set misc attributes
  444.                  * In fact, SDTA_Period and SDTA_Volume are calculated from SDTA_VoiceHeader info,
  445.                  * but we set it here EXPLICITLY that noone can say we didn't pass this to sound.datatype...
  446.                  */
  447.                 SetDTAttrs( o, NULL, NULL, SDTA_Sample,         aiff_sample,
  448.                                            SDTA_SampleLength,   aiff_samplelength,
  449.                                            SDTA_Period,         aiff_period,
  450.                                            SDTA_Volume,         aiff_volume,
  451.                                            TAG_DONE );
  452.               }
  453.               else
  454.               {
  455.                 /* the object did not support all attributes we want... */
  456.                 error = ERROR_OBJECT_WRONG_TYPE;
  457.               }
  458.             }
  459.             else
  460.             {
  461.               /* NewDTObject failed */
  462.               error = IoErr();
  463.             }
  464.           }
  465.         }
  466.         else
  467.         {
  468.           /* no filehandle */
  469.           error = ERROR_NO_FREE_STORE;
  470.         }
  471. #else
  472.         if( fh )
  473.         {
  474.           BPTR stdout      = Open( "CON:////MPEG Audio DataType/auto/close/wait/inactive", MODE_NEWFILE );
  475.           TEXT cmd[ 256 ];
  476.  
  477.           /* The '@' character at the beginning of the input filename option 
  478.            * means in my "maplay" version to use stdin as input
  479.            */
  480.           mysprintf( cb, (maid -> maid_8SVXName), "@%lx.8svx", o );
  481.           mysprintf( cb, cmd,                     "maplay:maplay -v @%lx", o );
  482.  
  483.           /* Start decoder "maplay" */
  484.           if( SystemTags( cmd, SYS_Input,      fh,
  485.                                SYS_Output,     stdout,
  486.                                NP_ConsoleTask, (((struct FileHandle *)BADDR( stdout )) -> fh_Type),
  487.                                NP_StackSize,   16384UL,
  488.                                TAG_DONE ) == 0L )
  489.           {
  490.           }
  491.           else
  492.           {
  493.             /* can't start "maplay" */
  494.             error = IoErr();
  495.           }
  496.  
  497.           Close( stdout );
  498.  
  499.           /* Success ? */
  500.           if( error == 0L )
  501.           {
  502. try:
  503.             maid -> maid_8SVXObject = NewDTObject( (maid -> maid_8SVXName), DTA_GroupID, GID_SOUND, TAG_DONE );
  504.  
  505.             /* This may happen if "maplay" has not been finished yet,,, */
  506.             if( ((maid -> maid_8SVXObject) == NULL) && (IoErr() == ERROR_OBJECT_IN_USE) )
  507.             {
  508.               /* Wait a 1/5 sec */
  509.               Delay( (TICKS_PER_SECOND / 5UL) );
  510.               goto try;
  511.             }
  512.  
  513.             if( maid -> maid_8SVXObject )
  514.             {
  515.               struct VoiceHeader *iff8svx_vh;
  516.               APTR                iff8svx_sample;
  517.               ULONG               iff8svx_samplelength;
  518.               ULONG               iff8svx_period;
  519.               ULONG               iff8svx_volume;
  520.  
  521.               if( GetDTAttrs( (maid -> maid_8SVXObject), SDTA_VoiceHeader,    (&iff8svx_vh),
  522.                                                          SDTA_Sample,         (&iff8svx_sample),
  523.                                                          SDTA_SampleLength,   (&iff8svx_samplelength),
  524.                                                          SDTA_Period,         (&iff8svx_period),
  525.                                                          SDTA_Volume,         (&iff8svx_volume),
  526.                                                          TAG_DONE ) == 5UL )
  527.               {
  528.                 /* Copy voiceheader. This point is very tricky because mpeg audio might not support all things... */
  529.                 *vh = *iff8svx_vh;
  530.  
  531.                 /* Set misc attributes
  532.                  * In fact, SDTA_Period and SDTA_Volume are calculated from SDTA_VoiceHeader info,
  533.                  * but we set it here EXPLICITLY that noone can say we didn't pass this to sound.datatype...
  534.                  */
  535.                 SetDTAttrs( o, NULL, NULL, SDTA_Sample,         iff8svx_sample,
  536.                                            SDTA_SampleLength,   iff8svx_samplelength,
  537.                                            SDTA_Period,         iff8svx_period,
  538.                                            SDTA_Volume,         iff8svx_volume,
  539.                                            TAG_DONE );
  540.               }
  541.               else
  542.               {
  543.                 /* the object did not support all attributes we want... */
  544.                 error = ERROR_OBJECT_WRONG_TYPE;
  545.               }
  546.             }
  547.             else
  548.             {
  549.               /* NewDTObject failed */
  550.               error = IoErr();
  551.             }
  552.           }
  553.         }
  554.         else
  555.         {
  556.           /* no filehandle */
  557.           error = ERROR_NO_FREE_STORE;
  558.         }
  559. #endif /* USE_MPEGA */
  560.       }
  561.     }
  562.     else
  563.     {
  564.       /* can't get required attributes from superclass */
  565.       error = ERROR_OBJECT_WRONG_TYPE;
  566.     }
  567.  
  568.     return( error );
  569. }
  570.  
  571.  
  572. static
  573. void mysprintf( struct ClassBase *cb, STRPTR buffer, STRPTR fmt, ... )
  574. {
  575.     APTR args;
  576.  
  577.     args = (APTR)((&fmt) + 1);
  578.  
  579.     RawDoFmt( fmt, args, (void (*))"\x16\xc0\x4e\x75", buffer );
  580. }
  581.  
  582.  
  583. #ifndef NO_ENCODER
  584. /* The MPEG Audio encoder */
  585. static
  586. ULONG SaveMPEGAudio( struct ClassBase *cb, Object *o, struct dtWrite *dtw )
  587. {
  588.     ULONG retval = 0UL;
  589.     LONG  error  = ERROR_NOT_IMPLEMENTED;
  590.  
  591. #if 0
  592.     /* A NULL file handle is a nop (GMultiView uses this to test if a datatype supports RAW writing) */
  593.     if( dtw -> dtw_FileHandle )
  594.     {
  595.     }
  596. #endif
  597.  
  598.     /* Store Result2 */
  599.     SetIoErr( error );
  600.  
  601.     return( retval );
  602. }
  603. #endif /* !NO_ENCODER */
  604.  
  605.  
  606.  
  607.  
  608.  
  609.